package com.libre.workflow.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.libre.auth.entity.User;
import com.libre.auth.service.UserService;
import com.libre.common.enums.ActionEnum;
import com.libre.common.exception.BusinessRuntimeException;
import com.libre.common.utils.DateTimeUtil;
import com.libre.common.utils.StringUtil;
import com.libre.common.vo.PageVo;
import com.libre.workflow.service.MyTaskService;
import com.libre.workflow.vo.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.util.CollectionUtil;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 庞留杰
 * @version V1.0
 * @description 流程任务
 * @date 2020/9/11 18:01
 **/
@Slf4j
@Service
@Transactional
public class MyTaskServiceImpl implements MyTaskService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private UserService userService;

    /**
     * 功能描述: 查询申请（查询我发起的流程实例）【对应表：act_hi_procinst 历史的流程实例表】
     *
     * @param applyVo
     * @throws
     * @author: 庞留杰
     * @return: Result
     * @date: 2020/9/16 17:44
     */
    @Override
    public Page apply(PageVo pageVo, MyApplyVo applyVo) {
        int size = pageVo.getPageSize();
        int current = pageVo.getPageNumber();
        int firstResult = (current - 1) * size;// 第一条数据
        int maxResults = size;// 每页多少条
        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();

        if (StringUtil.isNotEmpty(applyVo.getBusinessName())) {
            query.processInstanceNameLike("%" + applyVo.getBusinessName() + "%");
        }

        List<HistoricProcessInstance> historicProcessInstances = query.startedBy(applyVo.getUserId())
                .orderByProcessInstanceStartTime().desc() //开始时间倒序排列
                .listPage(firstResult, maxResults);
        JSONArray arr = new JSONArray();
        //查询所有用户信息
        List<User> allUsers = userService.list();
        historicProcessInstances.forEach(historicProcessInstance -> {
            JSONObject obj = new JSONObject();
            obj.put("processInstanceId", historicProcessInstance.getId());//流程实例ID:processInstanceId
            //执行实例ID（executionId）不返回，原因是：在多实例中，一个申请可能对应多个executionId，没意义
            obj.put("name", historicProcessInstance.getProcessDefinitionName());
            obj.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
            obj.put("processDefinitionKey", historicProcessInstance.getProcessDefinitionKey());
            obj.put("processDefinitionName", historicProcessInstance.getProcessDefinitionName());
            obj.put("description", historicProcessInstance.getDescription());
            obj.put("startTime", DateTimeUtil.format(historicProcessInstance.getStartTime(), DateTimeUtil.DATE_TIME));
            obj.put("endTime", DateTimeUtil.format(historicProcessInstance.getEndTime(), DateTimeUtil.DATE_TIME));
            obj.put("durationInMillis", historicProcessInstance.getDurationInMillis()); //审核过程耗时
            obj.put("deleteReason", historicProcessInstance.getDeleteReason());//删除原因
            //发起人
            User user = allUsers.stream().filter(u -> (u.getId()).equals(historicProcessInstance.getStartUserId())).findAny().orElse(null);
            if (user != null) {
                obj.put("startUserId", historicProcessInstance.getStartUserId());//发起人ID
                obj.put("startUserName", user.getRealName());//发起人
            } else {
                obj.put("startUserId", historicProcessInstance.getStartUserId());//发起人ID
                obj.put("startUserName", null);//发起人
            }
            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(historicProcessInstance.getId()).singleResult();
            String businessKey = processInstance.getBusinessKey();
            String businessName = processInstance.getName();
            obj.put("businessKey", businessKey);//业务Key
            obj.put("businessName", businessName);//业务名称
            //结束状态 0：进行中，1：已结束
            if (historicProcessInstance.getEndTime() != null) {//说明已经结束
                obj.put("endState", "1");
                obj.put("endStateCN", "已结束");
            } else {
                obj.put("endState", "0");
                obj.put("endStateCN", "进行中");
            }
            arr.add(obj);
        });
        Long count = query.count();
        Page page = new Page(current, size, count);
        page.setRecords(arr);
        return page;
    }

    /**
     * 功能描述: 根据用户ID或者用户组ID，查询该用户代办，查询该用户代办数量
     *
     * @param userId   用户ID
     * @param groupIds 用户组ID
     * @throws
     * @author: 庞留杰
     * @return:
     * @date: 2021/4/15 11:01
     */
    @Override
    public long count(String userId, List<String> groupIds) {
        long count = 0;
        if (CollectionUtil.isEmpty(groupIds)) {
            count = taskService.createTaskQuery().taskCandidateOrAssigned(userId).orderByTaskPriority().desc()
                    .orderByTaskCreateTime().asc()
                    .count();
        } else {
            count = taskService.createTaskQuery().taskCandidateOrAssigned(userId).taskCandidateGroupIn(groupIds).orderByTaskPriority().desc()
                    .orderByTaskCreateTime().asc()
                    .count();
        }
        return count;
    }

    /**
     * 功能描述: 根据用户ID或者用户组ID，查询该用户待办
     *
     * @param backlogVo
     * @throws
     * @author: 庞留杰
     * @return:
     * @date: 2021/4/15 11:01
     */
    @Override
    public Page backlog(PageVo pageVo, MyBacklogVo backlogVo) {
        // VerifyUtil.notEmpty("groupIds",backlogVo.getGroupIds());
        int size = pageVo.getPageSize();
        int current = pageVo.getPageNumber();
        int firstResult = ((current - 1) * size);// 第一条数据
        int maxResults = size;// 每页多少条
        TaskQuery taskQuery = taskService.createTaskQuery();// 查询条件
        if (StringUtils.isNotBlank(backlogVo.getUserId())) {  //代办人ID
            taskQuery.taskCandidateOrAssigned(backlogVo.getUserId());
        }
        if (backlogVo.getGroupIds() != null) { //代办分组ID,例：["ROLE_ADMIN", "ROLE_GROUP_LEADER"]
            List<String> groupIds = Arrays.asList(backlogVo.getGroupIds());
            taskQuery.taskCandidateGroupIn(groupIds);
        }
        if (StringUtils.isNotBlank(backlogVo.getBusinessKey())) {
            taskQuery.processInstanceBusinessKey(backlogVo.getBusinessKey());
        }
        if (StringUtils.isNotBlank(backlogVo.getProcessInstanceId())) {
            taskQuery.processInstanceId(backlogVo.getProcessInstanceId());
        }
        if (StringUtils.isNotBlank(backlogVo.getProcessDefinitionKey())) {
            taskQuery.processDefinitionKey(backlogVo.getProcessDefinitionKey());
        }
        //流程实例ID
        if (StringUtils.isNotBlank(backlogVo.getExecutionId())) {
            taskQuery.executionId(backlogVo.getExecutionId());
        }
        /**
         * 查询
         * */
        List<Task> taskList = taskQuery
                .includeProcessVariables()//在任务查询结果中包含全局任务变量
                .orderByTaskPriority().desc() //通过 TaskPriority 排序
                .orderByTaskCreateTime().desc() //通过 TaskCreateTime 排序
                .listPage(firstResult, maxResults);
        JSONArray arr = new JSONArray();
        //查询所有用户信息
        List<User> allUsers = userService.list();
        taskList.forEach(task -> {
            JSONObject obj = new JSONObject();
            obj.put("id", task.getId());
            //  obj.put("assignee", task.getAssignee());//签收人或者委托人
            //代办人
            User user = allUsers.stream().filter(u -> (u.getId()).equals(task.getAssignee())).findAny().orElse(null);
            if (user != null) {
                obj.put("assignee", task.getAssignee());//代办人ID
                obj.put("assigneeName", user.getRealName());//代办人
            } else {
                obj.put("assignee", task.getAssignee());//代办人ID
                obj.put("assigneeName", null);//代办人
            }
            obj.put("owner", task.getOwner());//（一般情况下为空，只有在委托时才有值）
            obj.put("name", task.getName());
            obj.put("variables", task.getProcessVariables());
            obj.put("createTime", DateTimeUtil.format(task.getCreateTime(), DateTimeUtil.DATE_TIME));
            obj.put("processInstanceId", task.getProcessInstanceId());//查询流程图
            obj.put("priority", task.getPriority());//优先级
            //isSuspended 如果流程实例被挂起，则返回true  （1挂起，2激活） 【对应act_ru_execution：SUSPENSION_STATE_】
            obj.put("isSuspended", task.isSuspended() == true ? 1 : 2);
            obj.put("isSuspendedCN", task.isSuspended() == true ? "挂起" : "激活");
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            String businessKey = processInstance.getBusinessKey();
            String businessName = processInstance.getName();
            String processDefinitionId = processInstance.getProcessDefinitionId();
            String processDefinitionKey = processInstance.getProcessDefinitionKey();
            String processDefinitionName = processInstance.getProcessDefinitionName();
            obj.put("businessKey", businessKey);
            obj.put("businessName", businessName);
            obj.put("processDefinitionId", processDefinitionId);
            obj.put("processDefinitionKey", processDefinitionKey);
            obj.put("processDefinitionName", processDefinitionName);
            obj.put("executionId", task.getExecutionId());//EXECUTION主键
            //  obj.put("startUserId", processInstance.getStartUserId());//流程发起人
            //发起人
            User user1 = allUsers.stream().filter(u -> (u.getId()).equals(processInstance.getStartUserId())).findAny().orElse(null);
            if (user1 != null) {
                obj.put("startUserId", processInstance.getStartUserId());//发起人ID
                obj.put("startUserName", user1.getRealName());//发起人
            } else {
                obj.put("startUserId", processInstance.getStartUserId());//发起人ID
                obj.put("startUserName", null);//发起人
            }
            arr.add(obj);
        });
        Long count = taskQuery.count();
        Page page = new Page(current, size, count);
        page.setRecords(arr);
        return page;
    }

    /**
     * 功能描述: 查询已办任务【对应表：act_hi_taskinst】
     *
     * @param finishedVo
     * @throws
     * @author: 庞留杰
     * @return:
     * @date: 2020/9/14 9:14
     */
    @Override
    public Page finished(PageVo pageVo, MyFinishedVo finishedVo) {
        String userId = finishedVo.getUserId();
        String businessKey = finishedVo.getBusinessKey();
        String businessName = finishedVo.getBusinessName();
        String businessType = finishedVo.getBusinessType();
        int size = pageVo.getPageSize();
        int current = pageVo.getPageNumber();
        int firstResult = ((current - 1) * size);// 第一条数据
        int maxResults = size;// 每页多少条
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery();
        if (StringUtils.isNotBlank(userId)) {
            query.taskAssignee(userId);
        }
        if (StringUtil.isNotEmpty(businessKey)) {
            query.processInstanceBusinessKey(businessKey + "");
        }
        if (StringUtil.isNotEmpty(businessType)) {
            query.processVariableValueLike("businessType", businessType);
        }
        List<HistoricTaskInstance> historicTaskInstances = query.finished()
                .includeProcessVariables().orderByHistoricTaskInstanceEndTime()
                .desc()
                .listPage(firstResult, maxResults);
        JSONArray arr = new JSONArray();
        //查询所有用户信息
        List<User> allUsers = userService.list();
        historicTaskInstances.forEach(historicTaskInstance -> {
            JSONObject obj = new JSONObject();
            obj.put("id", historicTaskInstance.getId());
            obj.put("executionId", historicTaskInstance.getExecutionId());
            obj.put("processInstanceId", historicTaskInstance.getProcessInstanceId());
            obj.put("processDefinitionId", historicTaskInstance.getProcessDefinitionId());
            obj.put("taskDefinitionId", historicTaskInstance.getTaskDefinitionId());
            //代办人
            User user = allUsers.stream().filter(u -> (u.getId()).equals(historicTaskInstance.getAssignee())).findAny().orElse(null);
            if (user != null) {
                obj.put("assignee", historicTaskInstance.getAssignee());//代办人ID
                obj.put("assigneeName", user.getRealName());//代办人
            } else {
                obj.put("assignee", historicTaskInstance.getAssignee());//代办人ID
                obj.put("assigneeName", null);//代办人
            }
            obj.put("createTime", DateTimeUtil.format(historicTaskInstance.getCreateTime(), DateTimeUtil.DATE_TIME));
            obj.put("endTime", DateTimeUtil.format(historicTaskInstance.getEndTime(), DateTimeUtil.DATE_TIME));
            obj.put("durationInMillis", historicTaskInstance.getDurationInMillis()); //审核过程耗时
            obj.put("name", historicTaskInstance.getName());
            obj.put("owner", historicTaskInstance.getOwner());//委托人（默认为空，只有在委托时才有值）
            //查询业务主键
            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(historicTaskInstance.getProcessInstanceId()).singleResult();
            if (processInstance != null) {
                //发起人
                User user1 = allUsers.stream().filter(u -> (u.getId()).equals(processInstance.getStartUserId())).findAny().orElse(null);
                if (user1 != null) {
                    obj.put("startUserId", processInstance.getStartUserId());//发起人ID
                    obj.put("startUserName", user1.getRealName());//发起人
                } else {
                    obj.put("startUserId", processInstance.getStartUserId());//发起人ID
                    obj.put("startUserName", null);//发起人
                }
                obj.put("businessKey", processInstance.getBusinessKey());
                obj.put("businessName", processInstance.getName());
                obj.put("processDefinitionKey", processInstance.getProcessDefinitionKey());
                obj.put("processDefinitionName", processInstance.getProcessDefinitionName());
            }
            arr.add(obj);
        });
        long count = query.count();
        Page page = new Page(current, size, count);
        page.setRecords(arr);
        return page;
    }

    /**
     * 功能描述: 执行任务
     * 任务执行类型 claim：签收 unclaim 反签收 complete 完成 delegate 任务委派 resolve 任务签收完成 返回任务人 assignee 任务转办
     *
     * @param executeVo
     * @throws
     * @author: 庞留杰
     * @return:
     * @date: 2021/4/15 11:03
     */
    @Override
    public Map<String, Object> executeTask(MyExecuteVo executeVo) {
        String taskId = executeVo.getTaskId();
        String action = executeVo.getAction();
        String userId = executeVo.getAssignee();
        Boolean localScope = executeVo.getLocalScope();
        Map<String, Object> variables = executeVo.getVariables();
        log.info(">>>>>>>>>>>>>> 签收任务ID：{}--签收类型：{}--签收人ID：{} >>>>>>>>>>>>>>", taskId, action, userId);
        localScope = (null == localScope) ? false : localScope;
        Map<String, Object> result = Maps.newHashMap();
        ActionEnum actionEnum = ActionEnum.actionOf(action);
        switch (actionEnum) {
            case COMPLETE:
                //完成任务
                result = this.complete(taskId, variables, localScope);
                break;
            case CLAIM:
                //签收任务
                this.claim(taskId, userId);
                break;
            case UNCLAIM:
                //反签收
                this.unClaim(taskId);
                break;
            case DELEGATE:
                //任务委派
                this.delegate(taskId, userId);
                break;
            case RESOLVE:
                //委派任务完成，归还委派人
                this.resolveTask(taskId);
                break;
            case ASSIGNEE:
                //任务转办
                this.setAssignee(taskId, userId);
                break;
            default:
                break;
        }
        return result;
    }

    public void claim(String taskId, String userId) {
        log.info(">>>>>>>>>>>>>> 签收任务ID：{}--签收人：{} >>>>>>>>>>>>>>", taskId, userId);
        taskService.claim(taskId, userId);
    }

    public void unClaim(String taskId) {
        log.info(">>>>>>>>>>>>>> 反签收任务：{} >>>>>>>>>>>>>>", taskId);
        taskService.unclaim(taskId);
    }

    public void complete(String taskId) {
        this.complete(taskId, null);
        log.info(">>>>>>>>>>>>>> 任务ID：{},已完成 >>>>>>>>>>>>>>", taskId);
    }

    public void complete(String taskId, Map<String, Object> variables) {
        log.info(">>>>>>>>>>>>>> 完成任务ID：{} >>>>>>>>>>>>>>", taskId);
        taskService.complete(taskId, variables);
    }

    public Map<String, Object> complete(String taskId, Map<String, Object> variables, boolean localScope) {
        Task finishTask = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (finishTask == null) {
            throw new RuntimeException("通过taskId：" + taskId + "未查询到task");
        }
        /**complete()
         * 当任务成功执行时调用，并由最终用户提供所需的任务参数。
         *
         * @param taskId  要完成的任务的id不能为null。
         * @param variables 任务参数。可以为空。
         * @param localScope 如果为真，所提供的变量将存储在任务本地，而不是流程实例范围(这是{@link #complete(String, Map)}的默认值)。
         * @throws FlowableObjectNotFoundException 当给定id没有任务存在时。
         */
        try {
            taskService.complete(taskId, variables, localScope);
        } catch (FlowableObjectNotFoundException e) {
            // taskId 不存在
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(finishTask.getProcessInstanceId()).active().list();
        Map<String, Object> map = new HashMap<>(16);
        Map<String, Object> finish = new HashMap<>(16);
        finish.put("id", finishTask.getId());
        finish.put("name", finishTask.getName());
        map.put("finish", finish);// 刚刚执行结束的task信息
        List<Map<String, Object>> taskList = new ArrayList<>();
        for (Task task : tasks) {
            Map<String, Object> taskMap = new HashMap<>(16);
            taskMap.put("id", task.getId());
            taskMap.put("name", task.getName());
            taskMap.put("processInstanceId", task.getProcessInstanceId());
            taskMap.put("executionId", task.getExecutionId());
            taskList.add(taskMap);
        }
        map.put("active", taskList);// 即将执行的task信息
        return map;
    }

    public void setAssignee(String taskId, String userId) {
        log.info(">>>>>>>>>>>>>> 移交任务ID：{}--,移交给用户ID：{} >>>>>>>>>>>>>>", taskId, userId);
        taskService.setAssignee(taskId, userId);
    }

    public void delegate(String taskId, String userId) {
        log.info(">>>>>>>>>>>>>> 委派任务ID：{}--,委派给用户：{} >>>>>>>>>>>>>>", taskId, userId);
        taskService.delegateTask(taskId, userId);
    }

    public void resolveTask(String taskId) {
        log.info(">>>>>>>>>>>>>> 委派完成任务ID：{} >>>>>>>>>>>>>>", taskId);
        taskService.resolveTask(taskId);
    }

    public void delete(String taskId) {
        log.info(">>>>>>>>>>>>>> 删除任务：任务ID：{} >>>>>>>>>>>>>>", taskId);
        taskService.deleteTask(taskId);
    }

    /**
     * 功能描述: 查询任务
     * @author: 庞留杰
     * @param taskListQuery
     * @return:
     * @exception
     * @date: 2021/4/15 11:06
     */
//    @Override
//    public JSONArray findTask(TaskListQuery taskListQuery) {
//        TaskQuery query = taskService.createTaskQuery();
//        if (StringUtils.isNotBlank(taskListQuery.getTaskId())) {
//            // 任务id查询单条记录
//           /*  Task task = query.taskId(taskListQuery.getTaskId()).includeProcessVariables().singleResult();
//            return task; */
//        }
//        if (StringUtils.isNotBlank(taskListQuery.getProcessInstanceId())) {
//            query.processInstanceId(taskListQuery.getProcessInstanceId());
//        }
//        List<Task> tasks = query.includeProcessVariables().list();
//        JSONArray arr = new JSONArray();
//        tasks.forEach(task -> {
//            JSONObject obj = new JSONObject();
//            obj.put("id", task.getId());
//            obj.put("name", task.getName());//taskName  合同主管审批
//            obj.put("taskDefinitionKey", task.getTaskDefinitionKey());
//            obj.put("description", task.getDescription());
//            obj.put("executionId", task.getId());
//            obj.put("processInstanceId", task.getProcessInstanceId());
//            obj.put("processDefinitionId", task.getProcessDefinitionId());
//            obj.put("createTime", DateTimeUtil.format(task.getCreateTime(), DateTimeUtil.DATE_TIME));
//            obj.put("dueDate", DateTimeUtil.format(task.getDueDate(), DateTimeUtil.DATE_TIME));//用户任务的到期日期(dueDate)
//            obj.put("owner", task.getOwner());
//            obj.put("assignee", task.getAssignee());
//            arr.add(obj);
//        });
//        return arr;
//    }

    /**
     * @description 添加备注信息
     * @param  commentVo
     * @author 庞留杰
     * @date 2020/9/14 9:34
     * @version V1.0
     **/
    @Override
    public void addComments(MyCommentVo commentVo) {
        String taskId = commentVo.getTaskId();
        String processInstanceId = commentVo.getProcessInstanceId();
        String message = commentVo.getMessage();
        String userId = commentVo.getUserId();
        log.info("----任务或者流程实例添加备注：任务ID:{},流程实例ID{}---------", taskId, processInstanceId);
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new BusinessRuntimeException("通过TaskId:【" + taskId + "】获取信息异常");
        }
        message = StringUtil.isNotEmpty(message) ? message : ""; //防止：当消息是null,flowable的AddCommentCmd方法会抛出异常
        Comment comment = taskService.addComment(taskId, processInstanceId, message);
        comment.setUserId(userId);
        taskService.saveComment(comment);
    }

//    /**
//     * @description 添加备注信息 （不需要taskId）
//     * @param  commentAddQuery
//     * {
//     *        processInstanceId:流程实例ID
//     *        message: 批注信息
//     *        userId: 用户ID
//     * }
//     * @author 庞留杰
//     * @date 2020/9/14 9:34
//     * @version V1.0
//     **/
//    @Override
//    public void addComments2(CommentAddQuery commentAddQuery) {
//        String processInstanceId = commentAddQuery.getProcessInstanceId();
//        String message = commentAddQuery.getMessage();
//        String userId = commentAddQuery.getUserId();
//        log.info("----任务或者流程实例添加备注：流程实例ID{}---------", processInstanceId);
//        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
//        if (list.size() == 0) {
//            throw new BusinessRuntimeException("添加评论信息异常");
//        }
//        Task task = list.get(0);
//        String taskId = task.getId();
//        message = StringUtil.isNotEmpty(message) ? message : ""; //防止：当消息是null,flowable的AddCommentCmd方法会抛出异常
//        Comment comment = taskService.addComment(taskId, processInstanceId, message);
//        comment.setUserId(userId);
//        taskService.saveComment(comment);
//    }
//
//    /**
//     * @description 查询备注信息
//     * @param processInstanceId： 流程实例ID
//     * @author 庞留杰
//     * @date 2020/9/14 9:37
//     * @version V1.0
//     **/
//    @Override
//    public List<Comment> findCommentList(String processInstanceId) {
//        List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId);
//        return comments;
//    }
//
//    /**
//     * 功能描述: 获取所有可回退的节点
//     * @author: 庞留杰
//     * @param processInstanceId
//     * @return:
//     * @exception
//     * @date: 2020/9/14 9:37
//     */
//    @Override
//    public Map<String, Object> getFallbackNode(String processInstanceId) {
//        //1.获取当前的流程实例
//        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//        String processDefinitionId = processInstance.getProcessDefinitionId();
//        // 获取所有节点信息，暂不考虑子流程情况
//        List<Process> processes = repositoryService.getBpmnModel(processDefinitionId).getProcesses();
//        List<Map<String, String>> list = Lists.newArrayList();
//        for (Process process : processes) {
//            Collection<FlowElement> flowElements = process.getFlowElements();
//            if (CollectionUtils.isNotEmpty(flowElements)) {
//                for (FlowElement flowElement : flowElements) {
//                    if (flowElement instanceof UserTask) {
//                        Map<String, String> map = Maps.newHashMap();
//                        //业务操作
//                        map.put("id", flowElement.getId());
//                        map.put("name", flowElement.getName());
//                        list.add(map);
//                    }
//                    if (flowElement instanceof SubProcess) {
//                        // ，，，
//                    }
//                }
//            }
//        }
//        list.sort((a, b) -> a.get("id").compareTo(b.get("id")));//排序
//        // 获取当前的task
//        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).active().singleResult();
//        /*if(task == null){
//            throw new BusinessRuntimeException("通过ProcessInstanceId:【"+processInstanceId+"】获取信息异常，可能一下原因造成：1.流程实例ID错误，2：当前节点处于并行网关中，3.流程已结束");
//        }*/
//        list = list.stream().filter(it -> it.get("id").compareTo(task.getTaskDefinitionKey()) < 0).collect(Collectors.toList());//过滤
//        Map<String, Object> map = Maps.newHashMap();
//        map.put("history_nodes", list);
//        if (task != null) {
//            map.put("current_node", task.getTaskDefinitionKey());
//            map.put("current_name", task.getName());
//        }
//        return map;
//    }
//
//    /**
//     * 功能描述: 获取所有可回退的节点
//     *          规则：
//     *          1.从历史获取所有审批过的节点信息
//     *          2.通过开始时间排序，去除历史中重复的节点
//     * @author: 庞留杰
//     * @param   processInstanceId
//     * @return:
//     * @exception
//     * @date: 2021/1/21 15:10
//     */
//    @Override
//    public Map<String, Object> getFallbackNode2(String processInstanceId) {
//        VerifyUtil.notEmpty("processInstanceId", processInstanceId);
//
//        // 当前task,不支持并行网关
//        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).active().singleResult();
//        //        if(task == null){
//        //            throw new BusinessRuntimeException("通过ProcessInstanceId:【"+processInstanceId+"】获取信息异常，可能一下原因造成：1.流程实例ID错误，2：当前节点处于并行网关中，3.流程已结束");
//        //        }
//        //过滤历史节点类型 只要开始 结束 任务节点类型的
//        List<String> activityTypeFilter = Lists.newArrayList("userTask");// 可以过滤的值："startEvent", "endEvent", "userTask" ,"sequenceFlow"等
//        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished()
//                .orderByHistoricActivityInstanceStartTime().asc().list()
//                .stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());
//
//        List<Map<String, String>> list = Lists.newArrayList();
//        collect.forEach(it -> {
//            long count = list.stream().filter(item -> it.getActivityId().equals(item.get("id") + "")).count();
//            if (count == 0 && !task.getTaskDefinitionKey().equals(it.getActivityId())) {//1.不存在2.不等于当前节点
//                Map<String, String> m = Maps.newHashMap();
//                //业务操作
//                m.put("id", it.getActivityId());
//                m.put("name", it.getActivityName());
//                list.add(m);
//            }
//        });
//        Map<String, Object> map = Maps.newHashMap();
//        map.put("history_nodes", list);
//        if (task != null) {
//            map.put("current_node", task.getTaskDefinitionKey());
//            map.put("current_name", task.getName());
//        }
//        return map;
//    }
//
//    /**
//     * 功能描述: 获取所有可回退的节点
//     *          规则：
//     *              从历史获取所有审批过的节点信息
//     *              带分页
//     * @author: 庞留杰
//     * @param   processInstanceId
//     * @return:
//     * @exception
//     * @date: 2021/1/21 15:10
//     */
//    @Override
//    public Map<String, Object> getFallbackNode3(String processInstanceId, PageVo pageVo) {
//        VerifyUtil.notEmpty("processInstanceId", processInstanceId);
//        int size = pageVo.getPage_size();
//        int current = pageVo.getPage_number();
//        int fromIndex = (current - 1) * size;// 每页多少条
//        int toIndex = current * size;// 每页多少条
//        // 当前task,不支持并行网关
//        // Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).active().singleResult();
//        // 支持并行网关
//        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
//        Task task = null;
//        if(tasks.size()==1){
//            task = tasks.get(0);
//        }
//        //        if(task == null){
//        //            throw new BusinessRuntimeException("获取信息异常，可能一下原因造成：1.流程实例ID错误，2：当前节点处于并行网关中，3.流程已结束");
//        //        }
//        //过滤历史节点类型 只要开始 结束 任务节点类型的
//        List<String> activityTypeFilter = Lists.newArrayList("userTask");// 可以过滤的值："startEvent", "endEvent", "userTask" ,"sequenceFlow"等
//        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished()
//                .orderByHistoricActivityInstanceStartTime().asc().list()
//                .stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());
//        List<Map<String, Object>> list = Lists.newArrayList();
//        int count = collect.size();
//        if (toIndex > count) {
//            toIndex = count;
//        }
//        collect = collect.subList(fromIndex, toIndex);
//        //查询所有用户信息
//        List<Map<String, Object>> allUsers = myService.findAllUsers();
//        collect.forEach(his -> {
//            Map<String, Object> m = Maps.newHashMap();
//            //业务操作
//            m.put("id", his.getActivityId());
//            m.put("name", his.getActivityName());
//            //操作人
//            Map<String, Object> map = allUsers.stream().filter(e -> (e.get("id") + "").equals(his.getAssignee())).findAny().orElse(null);
//            if (map != null) {
//                m.put("assignee", his.getAssignee());//操作人ID
//                m.put("assigneeName", map.get("real_name"));//操作人
//            } else {
//                m.put("assignee", his.getAssignee());//操作人ID
//                m.put("assigneeName", null);//操作人
//            }
//            m.put("startTime", DateTimeUtil.format(his.getStartTime(), DateTimeUtil.DATE_TIME));
//            m.put("endTime", DateTimeUtil.format(his.getEndTime(), DateTimeUtil.DATE_TIME));
//            m.put("durationInMillis", his.getDurationInMillis());//耗时
//            //备注信息
//            List<Comment> taskComments = taskService.getTaskComments(his.getTaskId());
//            List<Map> comments = Lists.newArrayList();
//            taskComments.forEach(com -> {
//                Map<String, Object> comment = Maps.newHashMap();
//                comment.put("time", DateTimeUtil.format(com.getTime(), DateTimeUtil.DATE_TIME));
//                comment.put("message", com.getFullMessage());
//                comments.add(comment);
//            });
//            m.put("comments", comments);
//            list.add(m);
//        });
//        Page page = new Page(current, size, count);
//        page.setRecords(list);
//        page.setTotal(count);
//        Map<String, Object> map = new HashMap<>();
//        map.put("history_nodes", page);
//        if (task != null) {
//            map.put("current_node", task.getTaskDefinitionKey());
//            map.put("current_name", task.getName());
//        }
//        return map;
//    }
//
//
//    /**
//     * 功能描述: 任务撤回【注意：当前与目标定义Key为设计模板时任务对应的ID(通常格式：sid-xxxxxxxxxxxxxxxxx),而非数据主键ID】
//     * @author: 庞留杰
//     * @param taskFallbackQuery
//     *         processInstanceId ：流程实例ID
//     *         currentTaskKey ：当前任务定义Key
//     *         targetTaskKey ：目标任务定义Key
//     * @return:
//     * @exception
//     * @date: 2021/1/21 11:18
//     */
//    @Override
//    public void withdraw(TaskFallbackQuery taskFallbackQuery) {
//        VerifyUtil.notEmpty("processInstanceId", taskFallbackQuery.getProcessInstanceId());
//        VerifyUtil.notEmpty("currentTaskKey", taskFallbackQuery.getCurrentTaskKey());
//        VerifyUtil.notEmpty("targetTaskKey", taskFallbackQuery.getTargetTaskKey());
//        log.info(">>>>>>>>>>>>>> 任务撤回：流程实例ID:{},当前活动任务ID:{},撤回到达的任务ID:{}，>>>>>>>>>>>>>>", taskFallbackQuery.getProcessInstanceId(), taskFallbackQuery.getCurrentTaskKey(), taskFallbackQuery.getTargetTaskKey());
//        try {
//            // 对于（并行网关，包含网关，多实例）禁止回退
//            prohibitFallback(taskFallbackQuery.getProcessInstanceId(), taskFallbackQuery.getTargetTaskKey());
//            // 回退处理
//            runtimeService.createChangeActivityStateBuilder()
//                    .processInstanceId(taskFallbackQuery.getProcessInstanceId())
//                    //并行网关不能用
//                    .moveActivityIdTo(taskFallbackQuery.getCurrentTaskKey(), taskFallbackQuery.getTargetTaskKey())
//                    .changeState();
//        } catch (FlowableObjectNotFoundException e) {
//            log.info("报错：{}", e);
//            throw new BusinessRuntimeException("任务撤回失败");
//        }
//    }
//
//    //对于并行网关，包含网关，多实例 直接不允许回退
//    public void prohibitFallback(String processInstanceId, String targetTaskKey) {
//        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//        if (pi == null) {
//            throw new BusinessRuntimeException("通过流程实例ID[" + processInstanceId + "]，未查到流程，请确认流程实例ID是否正确");
//        }
//        Process process = repositoryService.getBpmnModel(pi.getProcessDefinitionId()).getMainProcess();
//        /* ParallelGateway并行网关
//         *  InclusiveGateway 包容网关
//         *  MultiInstanceActivityBehavior 多实例
//         */
//        // 通过flowElementId查询所有节点，包含子节点，如果searchRecursive=false，或者不传，不会查询子流程内的节点
//        Activity targetFlowElement = (Activity) process.getFlowElement(targetTaskKey, true);
//        if (targetFlowElement == null) {
//            throw new BusinessRuntimeException("通过目标节点ID[" + targetTaskKey + "]未查到节点信息，请确认目标节点ID是否正确");
//        }
//        String targetName = targetFlowElement.getName();
//        List<SequenceFlow> incomingFlows = targetFlowElement.getIncomingFlows();// 获取的值 (上个节点sid->当前节点的sid)
//        if (CollectionUtils.isNotEmpty(incomingFlows)) {
//            for (SequenceFlow sequenceFlow : incomingFlows) {
//                FlowElement upNode = sequenceFlow.getSourceFlowElement();
//                /***********************************并行网关*********************************/
//                if (upNode instanceof ParallelGateway) {// 并行网关
//                    String msg = String.format("回退的节点“%s”处于并行网关中，不允许回退，请选择其他节点回退", targetName);
//                    throw new BusinessRuntimeException(msg);
//                }
//                /***********************************包容网关*********************************/
//                if (upNode instanceof InclusiveGateway) {// 包容网关
//                    String msg = String.format("回退的节点“%s”处于包容网关中，不允许回退，请选择其他节点回退", targetName);
//                    throw new BusinessRuntimeException(msg);
//                }
//            }
//        }
//        /***********************************多实例*********************************/
//        if (isSubprocessActive(process, targetTaskKey)) {//当前节点在子流程内部
//            if (targetFlowElement instanceof UserTask) {//只是普通节点
//                FlowElementsContainer parentContainer = targetFlowElement.getParentContainer();
//                Activity activity = (Activity) parentContainer;
//                if (activity.getBehavior() instanceof MultiInstanceActivityBehavior) {//判断父节点是否是多实例
//                    String msg = String.format("回退的节点“%s”，处于多实例的子流程中，不允许回退，请选择其他节点回退", targetName);
//                    throw new BusinessRuntimeException(msg);
//                }
//            } else {
//                if (targetFlowElement != null && targetFlowElement.getBehavior() instanceof MultiInstanceActivityBehavior) {//多实例
//                    String msg = String.format("回退的节点“%s”属于多实例节点，不允许回退，请选择其他节点回退", targetName);
//                    throw new BusinessRuntimeException(msg);
//                }
//            }
//        } else {
//            if (!(targetFlowElement instanceof UserTask)) {//不是普通节点
//                if (targetFlowElement != null && targetFlowElement.getBehavior() instanceof MultiInstanceActivityBehavior) {//多实例
//                    String msg = String.format("回退的节点“%s”属于多实例节点，不允许回退，请选择其他节点回退", targetName);
//                    throw new BusinessRuntimeException(msg);
//                }
//            }
//        }
//    }
//
//    // 判断是否是子流程中的节点:false:不是，true:是
//    public boolean isSubprocessActive(Process process ,String activityId){
//        FlowElement flowElement1 = process.getFlowElement(activityId, false);
//        FlowElement flowElement2 = process.getFlowElement(activityId, true);
//        if(flowElement1 == null && flowElement2 == null){
//            throw new BusinessRuntimeException(String.format("通过activityId:%s，查询不到该节点",activityId));
//        }
//        if(flowElement1 != null){
//            return false;
//        } else {
//            return true;
//        }
//    }
//
//
//    /**
//     * 功能描述: 退回上一步，注意只能回退一步【例： 当前在“第三步”：
//     *                              调用一次，回退到“第二步”，
//     *                              再次调用，回退到“第三步”，
//     *                              再次调用，回退到“第二步”，
//     *                                以此类推。。。。
//     *           】
//     * @author: 庞留杰
//     * @param processInstanceId：流程实例ID
//     * @return:
//     * @exception
//     * @date: 2021/1/21 11:20
//     */
//    @Override
//    public Map<String, String> rollback(String processInstanceId) {
//        VerifyUtil.notEmpty("processInstanceId", processInstanceId);
//        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
//        if (task == null) {
//            throw new BusinessRuntimeException("流程实例processInstanceId：" + processInstanceId + "，不正确");
//        }
//        String currentTaskKey = task.getTaskDefinitionKey();//当前节点id
//        //过滤历史节点类型 只要:任务节点类型的
//        List<String> activityTypeFilter = Lists.newArrayList("userTask");
//        //审批历史数据
//        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished()
//                .orderByHistoricActivityInstanceEndTime().desc().list().stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());
//        if (collect.size() <= 0) {
//            throw new BusinessRuntimeException("流程尚未未开始审核，无法回退");
//        }
//        String targetTaskKey = collect.get(0).getActivityId();//审批历史中上一个节点id
//        // collect.forEach(it->{
//        //   log.info(">>>>>>>>>>>>>历史节点>>>>>>>>>>>>>"+it);
//        // });
//        log.info(">>>>>>>>>>>>> 任务回退：流程实例ID:{}，当前审批节点-ID:{}-NAME:{}，回退节点ID:{}-NAME:{} >>>>>>>>>>>>>",
//                processInstanceId,
//                task.getTaskDefinitionKey(), task.getName(),
//                collect.get(0).getActivityId(), collect.get(0).getActivityName());
//        try {
//            // 流程回退到上一个节点，审批人继续审批
//            runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
//                    .moveActivityIdTo(currentTaskKey, targetTaskKey).changeState();
//        } catch (FlowableObjectNotFoundException e) {
//            log.info("报错：{}", e);
//            throw new BusinessRuntimeException("任务回退失败");
//        }
//        Map<String, String> map = Maps.newHashMap();
//        map.put("from", currentTaskKey);//从哪个id开始回退
//        map.put("to", targetTaskKey);//回退到哪个id
//        return map;
//    }
//
//

    /**
     * 功能描述: 审批历史记录, 查看任务执行的详情【对应表：act_hi_actinst历史节点表】
     *
     * @param recordsVo
     * @throws
     * @author: 庞留杰
     * @return:
     * @date: 2020/9/16 19:38
     */
    @Override
    public Page records(PageVo pageVo, MyRecordsVo recordsVo) {
        int size = pageVo.getPageSize();
        int current = pageVo.getPageNumber();
        int fromIndex = (current - 1) * size;// 每页多少条
        int toIndex = current * size;// 每页多少条
        List<String> filterEvents = null;
        //过滤历史节点类型 只要开始 结束 任务节点类型的
        if (CollectionUtil.isEmpty(filterEvents)) {
            filterEvents = Lists.newArrayList("startEvent", "endEvent", "userTask");// "sequenceFlow"
        }
        List<String> activityTypeFilter = filterEvents;
        List<HistoricActivityInstance> collect = historyService.createHistoricActivityInstanceQuery().processInstanceId(recordsVo.getProcessInstanceId()).finished()
                .orderByHistoricActivityInstanceEndTime().desc().list()
                .stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());

//        下面方式有问题，通过executionId查询的历史中，多实例内部的可以查询处理，外部的内容都会过滤掉
//        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//        historicActivityInstanceQuery.processInstanceId(processInstanceId);
//         多实例
//        if(StringUtils.isNotEmpty(executionId)){
//            historicActivityInstanceQuery.executionId(executionId);
//        }
//        List<HistoricActivityInstance> collect = historicActivityInstanceQuery.finished()//查询已经结束的记录
//                .orderByHistoricActivityInstanceEndTime().desc().list()//排序字段，方式
//                .stream().filter(his -> activityTypeFilter.contains(his.getActivityType())).collect(Collectors.toList());//过滤需要的类型

        // 走过的节点
        Map<String, String> nodes = new HashMap<>();
        for (HistoricActivityInstance his : collect) {
            nodes.put(his.getActivityId(), his.getActivityName());
        }

        int count = collect.size();
        if (toIndex > count) {
            toIndex = count;
        }
        collect = collect.subList(fromIndex, toIndex);
        // 增加备注信息
        List<Map<String, Object>> historics = Lists.newArrayList();
        //查询所有用户信息
        List<User> allUsers = userService.list();
        for (HistoricActivityInstance his : collect) {
            Map<String, Object> historic = Maps.newHashMap();
            /******** 审批历史中的字段 start *******/
            historic.put("id", his.getId());
            historic.put("activityId", his.getActivityId());
            historic.put("activityName", his.getActivityName());
            historic.put("activityType", his.getActivityType());
            historic.put("processDefinitionId", his.getProcessDefinitionId());
            historic.put("processInstanceId", his.getProcessInstanceId());
            historic.put("executionId", his.getExecutionId());
            historic.put("taskId", his.getTaskId());
            historic.put("calledProcessInstanceId", his.getCalledProcessInstanceId());
            //操作人
            User user = allUsers.stream().filter(u -> (u.getId()).equals(his.getAssignee())).findAny().orElse(null);
            if (user != null) {
                historic.put("assignee", his.getAssignee());//操作人ID
                historic.put("assigneeName", user.getRealName());//操作人
            } else {
                historic.put("assignee", his.getAssignee());//操作人ID
                historic.put("assigneeName", null);//操作人
            }
            historic.put("startTime", DateTimeUtil.format(his.getStartTime(), DateTimeUtil.DATE_TIME));
            historic.put("endTime", DateTimeUtil.format(his.getEndTime(), DateTimeUtil.DATE_TIME));
            historic.put("durationInMillis", his.getDurationInMillis());//耗时
            historic.put("deleteReason", his.getDeleteReason());//删除原因
            historic.put("tenantId", his.getTenantId());
            /**
             * 回退信息处理：
             * deleteReason:如果设置了任何删除原因，则返回此活动的删除原因(如果正常完成，则没有设置删除原因)
             *              回退原因：Change activity to sid-1
             * */
            if (StringUtil.isNotEmpty(his.getDeleteReason()) && his.getDeleteReason().contains("Change activity to ")) {
                String deleteReason = his.getDeleteReason();
                String sid = deleteReason.replace("Change activity to ", "").trim();
                String nodeName = nodes.get(sid);//回退到节点
                historic.put("rollback", "由节点【" + his.getActivityName() + "】回退至节点【" + nodeName + "】");
                historic.put("deleteReason", deleteReason);
            }
            /**
             * 回退信息处理：
             * deleteReason:如果设置了任何删除原因，则返回此活动的删除原因(如果正常完成，则没有设置删除原因)
             *              回退原因：Change activity to sid-1
             * */
            if (StringUtil.isNotEmpty(his.getDeleteReason()) && his.getDeleteReason().contains("Change activity to ")) {
                String deleteReason = his.getDeleteReason();
                String sid = deleteReason.replace("Change activity to ", "").trim();
                String nodeName = nodes.get(sid);//回退到节点
                historic.put("rollback", "由节点【" + his.getActivityName() + "】回退至节点【" + nodeName + "】");
                historic.put("deleteReason", deleteReason);
            }
            /******** 审批历史中的字段 end *******/
            //备注信息
            List<Comment> taskComments = taskService.getTaskComments(his.getTaskId());
            List<Map<String, Object>> comments = Lists.newArrayList();
            taskComments.forEach(c -> {
                Map<String, Object> comment = Maps.newHashMap();
                //操作人
                User user1 = allUsers.stream().filter(u -> (u.getId()).equals(c.getUserId())).findAny().orElse(null);
                comment.put("userId", c.getUserId());
                comment.put("userName", user1 != null ? user1.getRealName() : "");
                comment.put("fullMessage", c.getFullMessage());
                comment.put("time", DateTimeUtil.format(c.getTime(), DateTimeUtil.DATE_TIME));
                comments.add(comment);
            });
            historic.put("comments", comments);
            //审批历史
            historics.add(historic);
        }
        Page page = new Page(current, size, count);
        page.setRecords(historics);
        page.setTotal(count);
        return page;
    }
//
//
//
//    // 不支持串行网关
//    @Override
//    public String getTaskIdByProcessInstanceId(String processInstanceId) {
//        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).active().singleResult();
//        String taskId = "";
//        if(task != null){
//            taskId = task.getId();
//        }
//        return taskId;
//    }


}
